#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

// For the Adafruit shield, these are the default.
//#define TFT_DC 9
//#define TFT_CS 10
#define TFT_DC D1
#define TFT_CS D8
#define TFT_MOSI D7
#define TFT_CLK D5
#define TFT_RST D2
#define TFT_MISO D6

//定义聊天框的全局信息
int line_max_length = 30; //每行最多的字数
int line_show_num = 28;   //最多显示多少行信息，多的要隐藏
//int line_show_num = 20; //使用80MHZ显示行数少避免崩溃
int char_width = 6;   //一个字符的宽度
//int char_height = 14; //使用80MHZ显示行数少避免崩溃
int char_height = 10; //一个字符的高度

int total_msg_height = 0;

std::vector<int> chat_modes;
std::vector<String> messages;

// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// If using the breakout, change pins as desired
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST);

void setup()
{
  Serial.begin(115200);
  tft.begin();
  initScreen();
}

//初始化UI界面
void initScreen()
{
  //设置背景颜色
  tft.fillScreen(ILI9341_BLACK);
  yield();

  //设置状态灯
  tft.fillCircle(15, 10, 5, ILI9341_RED);

  //设置状态信息
  tft.setCursor(30, 6);
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(1);
  tft.println("No Connection");

  //设置聊天框
  tft.drawRect(5, 20, tft.width() - 10, tft.height() - 30, ILI9341_WHITE);
}

/*
 * 改变连接状态
 * 
 * con_mode:
 *  0: 未连接，亮红灯
 *  1: 成功连接，亮绿灯
 *  2: 连接错误，亮黄灯
 *  
 * text：
 *  连接信息展示，未连接显示No Connection，连接成功显示对方ip，连接错误显示对应的错误信息
 */
void changeConState(int con_mode, String text)
{
  //画个框框盖住字，省去刷新全屏的时间
  tft.fillRect(30, 6, tft.width() - 30, char_height, ILI9341_BLACK);
  //
  switch (con_mode)
  {
  case 0:
    tft.fillCircle(15, 10, 5, ILI9341_RED);
    break;
  case 1:
    tft.fillCircle(15, 10, 5, ILI9341_GREEN);
    break;
  case 2:
    tft.fillCircle(15, 10, 5, ILI9341_YELLOW);
    break;
  }
  tft.setCursor(30, 8);
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(1);
  tft.println(text.c_str());
}

void showChat()
{
  //消息总行数
  int len = messages.size();

  int i = 0;
  if (len > line_show_num)
    i = len - line_show_num;
  int line_num = len - i;
  int cur_line = 1;
  
  //更新消息总高度以加快前期消息更新速度
  total_msg_height = len * char_height;
  if (total_msg_height >= tft.height() - 34)
    total_msg_height = tft.height() - 34;
  //重置聊天框
  tft.fillRect(7, tft.height() - total_msg_height - 12, tft.width() - 14, total_msg_height, ILI9341_BLACK);

  for (; i < len; i++)
  {
    String cur_msg = messages.at(i);
    int text_len = cur_msg.length();
    int text_width = char_width * text_len;
    int text_height = char_height * (line_num - cur_line + 1);
    cur_line++;
    int x = 0;
    int y = tft.height() - text_height - 10;
    if (chat_modes.at(i) == 0)
    {
      x = tft.width() / 2 - text_width / 2;
      tft.setTextColor(ILI9341_YELLOW);
    }
    else //如果是系统提示信息，应该居中，不考虑超出范围（不允许）
        if (chat_modes.at(i) == 1)
    {
      x = 10;
      tft.setTextColor(ILI9341_GREEN);
    }
    else //如果是系统提示信息，应该居中，不考虑超出范围（不允许）
        if (chat_modes.at(i) == 2)
    {
      x = tft.width() - text_width - 10;
      tft.setTextColor(ILI9341_RED);
    }
    tft.setCursor(x, y);
    tft.setTextSize(1);
    tft.println(cur_msg);
  }
}

/*
 * 显示聊天信息
 * 
 * chat_mode:
 *  0: 系统提示信息
 *  1: 我方信息
 *  2: 对方信息
 *  
 * text：
 *  聊天信息显示，自动换行等逻辑在内部处理
 */
void addChat(int msg_mode, String text)
{
  //文本长度
  int text_line = text.length();
  //文本行数计算
  int lineNum = text_line / line_max_length + 1;
  //若行数刚刚好，则无需+1
  if (text_line % line_max_length == 0)
    lineNum--;

  //把内容切割放入messages中
  for (int i = 0; i < lineNum; i++)
  {
    chat_modes.push_back(msg_mode);
    if (text.length() > line_max_length)
    {
      messages.push_back(text.substring(0, line_max_length));
    }
    else
    {
      messages.push_back(text);
    }
    text = text.substring(line_max_length);
  }
  //更新聊天窗口
  showChat();
}

void loop(void)
{
  //demo测试样例

  //等待连接示例
  addChat(0, "Waitting Connection...");
  changeConState(0, "No Connection");
//  delay(1000);

  //成功连接示例和发送消息示例
  addChat(1, "Hello Client");
//  delay(1000);

  //对方消息示例
  addChat(2, "Hi Server");
//  delay(1000);

  //连接中断示例和发送消息示例
  addChat(0, "Connection Error");
  changeConState(2, "Connection Error");
//  delay(1000);
}
